package com.hontech.bread.device


import com.hontech.bread.R
import com.hontech.bread.device.mdb.MdbFrame
import com.hontech.bread.utils.ExecException
import com.hontech.bread.utils.stringById
import serial.codec.CodecType
import serial.decodeU8
import serial.encodeU8
import serial.usb.xorSum

class Frame(val buf: ByteArray) {

    companion object {

        const val HEAD0 = 0xE1
        const val HEAD1 = 0x1E
        const val END = 0xEF
        const val MIN_LEN = 7

        fun makeAck(seq: Int) = make(Type.ACK, seq)
        fun makePong(seq: Int) = make(Type.PONG, seq)
        fun makeSession(seq: Int) = make(Type.SESSION, seq)

        fun make(type: Int, seq: Int, vararg args: CodecType): ByteArray {
            var len = MIN_LEN
            for (arg in args) {
                len += arg.size()
            }
            val buf = ByteArray(len)
            encodeU8(buf, 0, HEAD0)
            encodeU8(buf, 1, HEAD1)
            encodeU8(buf, 2, len)
            encodeU8(buf, 3, type)
            encodeU8(buf, 4, seq)
            var index = 5
            for (arg in args) {
                arg.encode(buf, index)
                index += arg.size()
            }
            val s = xorSum(buf, 3, len - 5)
            encodeU8(buf, index, s)
            encodeU8(buf, index + 1, END)
            return buf
        }
    }

    val type = decodeU8(buf, 0)
    val seq = decodeU8(buf, 1)

    fun cmd() = decodeU8(buf, 2)
    fun ec() = decodeU8(buf, 3)

    fun id() = (type shl 8) + seq

    fun toMdb(): MdbFrame {
        if (buf.size <= 4) {
            throw ExecException(stringById(R.string.err_mdb_timeout))
        }
        return MdbFrame(buf, 2, buf.size - 4)
    }

    fun parse(vararg args: CodecType) {
        var index = 3
        if ((type == Type.SIMPLE_RES) || (type == Type.RES)) {
            val ec = ec()
            if (ec != 0) {
                throw ExecException(errMsg(ec))
            }
            index = 4
        }
        for (arg in args) {
            arg.decode(buf, index)
            index += arg.size()
        }
    }
}
